package cn.com.utils.crypto;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Base64;

/**
 * cryto工具 加解密对外API
 */
@Slf4j
public class CrytoUtil {

    private static final String DECRYPT_PREFIX = "cryto.decrypt.identification";

    private static final String SPLIT_SIGN = "cryto.decrypt.split.sign";

    /**
     * 加密字符中的前缀
     */
    private static final String PREFIX_STRING;

    /**
     * 分隔符
     */
    private static final String SPLIT_SIGN_STRING;

    static {
        PREFIX_STRING = SettingUtils.get(DECRYPT_PREFIX);
        SPLIT_SIGN_STRING = SettingUtils.get(SPLIT_SIGN);
    }

    /**
     * 是否加密数据
     *
     * @param data 数据
     * @return boolean
     */
    public static boolean isEncryptedData(String data) {
        return StrUtil.isNotBlank(data) && data.startsWith(PREFIX_STRING);
    }

    /**
     * 解密数据。判断前后缀是否包含，如果有则排除
     *
     * @param data 要解密的数据
     * @return 解密后的数据。
     */
    public static String decrypt(String data) {
        return decrypt(data, true);
    }

    /**
     * 解密数据。
     *
     * @param data      要解密的数据
     * @param hasPrefix 需要解密的数据是否有前缀，如果有前缀，解密前需要去掉。
     * @return 解密后的数据。
     */
    public static String decrypt(String data, boolean hasPrefix) {
        if (StrUtil.isEmpty(data)) {
            return data;
        }
        if (hasPrefix) {
            if (data.startsWith(PREFIX_STRING + SPLIT_SIGN_STRING)) {
                data = data.replace(PREFIX_STRING + SPLIT_SIGN_STRING, "");
            }
            if (data.startsWith(PREFIX_STRING)) {
                data = data.replace(PREFIX_STRING, "");
            }
        }
        return DataCryptoUtil.decrypt(data);
    }

    /**
     * 使用工作密钥加密数据。
     *
     * @param data 要加密的数据。
     * @return 数据正在使用工作密钥进行加密。
     */
    public static String encrypt(String data) {
        return encrypt(data, true);
    }

    /**
     * 使用工作密钥加密数据。
     *
     * @param data       要加密的数据。
     * @param withPrefix 是否为加密字符串添加前缀。
     * @return 加密的数据。
     */
    public static String encrypt(String data, boolean withPrefix) {
        if (withPrefix) {
            return PREFIX_STRING + DataCryptoUtil.encrypt(data);
        } else {
            return DataCryptoUtil.encrypt(data);
        }
    }

    /**
     * [非对称加密] 返回非对称密钥对的公钥
     *
     * @return 非对称密钥对的公钥。
     */
    public static String getAsymmetricPublicKey() {
        return KeyCryptoUtil.getPublicKey();
    }


    /**
     * [非对称rsa加密] 使用公钥解密数据。
     *
     * @param data 要加密的数据。
     * @return 数据正在使用公钥解密。
     */
    public static String rsaDecrypt(String data) {
        return KeyCryptoUtil.decryptPub(data, KeyCryptoUtil.getPublicKey());
    }

    /**
     * [非对称rsa加密] 使用私钥解密数据。
     *
     * @param data 要加密的数据。
     * @return 数据正在使用公钥解密。
     */
    public static String asymmetricDecrypt(String data) {
        return KeyCryptoUtil.decryptPub(data, KeyCryptoUtil.getPrivateKey());
    }

    /**
     * [非对称加密] 使用公钥加密数据。
     *
     * @param data 要加密的数据。
     * @return 数据正在使用公钥加密。
     */
    public static String asymmetricEncrypt(String data) {
        return KeyCryptoUtil.encrypt(data, KeyCryptoUtil.getPublicKey());
    }

    /**
     * 哈希编码
     *
     * @param data 原生数据
     * @return 哈希结果
     */
    public static String encodeHash(String data) {
        return JSONUtil.toJsonStr(DataCryptoUtil.encode(data));
    }

    /**
     * 验证哈希
     *
     * @param data     数据
     * @param hashData 散列数据
     * @return boolean 验证结果
     */
    public static boolean validateHash(String data, String hashData) {
        Credential credential = JSONUtil.toBean(hashData, Credential.class);
        String salt = credential.getSalt();

        String hash = DataCryptoUtil.encodeHash(data, Base64.getDecoder().decode(salt), credential.getHashIteration());
        return StrUtil.equals(hash, credential.getSecretData());
    }
}
